/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Logica.Comandos;

import Logica.Fabricas.Comando;
import ObjetoDominio.Archivo;
import ObjetoDominio.ArchivoXML;
import ObjetoDominio.Servidor;
import ObjetoDominio.Usuario;
import Proxy.ProxyUsuario;
import Session.Session;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 *Comando que realiza la carga de un archivo de un usuario en especifico
 * @author opr
 */
public class ComandoIniciarCarga implements Comando<Boolean> {

    private Socket _cliente;
    private Usuario _usuario;
    private Archivo _archivo;
    private List<ObjectOutputStream> _listaDistribucionSalida = new ArrayList<ObjectOutputStream>();
    private List<DataInputStream> _listaDistribucionEntrada = new ArrayList<DataInputStream>();
    /**
     * Constructor de la clase
     * @param cliente socket de la comunbicacio con el cliente
     * @param usuario datos del usuario conectado
     * @param archivo datos del archivo a almacenar
     */
    public ComandoIniciarCarga(Socket cliente, Usuario usuario, Archivo archivo){
        
        _cliente = cliente;
        _usuario = usuario;
        _archivo = archivo;
    }
    
    /**
     * Metodo que se encarga de verificar en cuanto se dejo la descarga en 
     * caso que se haya iniciado la carga y no se hubiera culminado
     * satisfactoriamente
     * @return 0 si no el archivo no existia y -1 si el archivo ya existe y esta 
     * completo
     */
    private long comprobarDescargado(){
        try {
            
            File archivo = new File(_usuario.getNombre() + "/" +
                    _archivo.getNombre());
            if(archivo.length() < _archivo.getTamaño())
                return archivo.length();
            else if(archivo.length() > _archivo.getTamaño()) 
                return -2;
            else
                return -1;
            
        }catch (Exception e) {
            return 0;
        }
    }
    
    private void Sincronizar(){
        try {
            for (Servidor servidor : Session.getServidores()) {
                servidor.AbrirConexion();
                if(servidor.isActivo()){
                    OutputStream flujoSalida = servidor.getViaComunicacion().getOutputStream();
                    InputStream flujoEntrada = servidor.getViaComunicacion().getInputStream();
                    DataOutputStream salida = new DataOutputStream( flujoSalida );
                    salida.writeUTF(ArchivoXML.CrearMensaje("cargarServidor"));
                    salida.writeUTF(ProxyUsuario.TransformarUsuarioXml(_usuario));
                    salida.writeUTF(ArchivoXML.CrearMensaje(_archivo.getNombre()));
                    salida.writeUTF(ArchivoXML.CrearMensaje(String.valueOf(_archivo.getTamaño())));
                    DataInputStream entrada = new DataInputStream(flujoEntrada);
                    long respuesta = Long.parseLong(ArchivoXML.ObtenerMensaje(entrada.readUTF()));
                    servidor.CerrarConexion();
                    if(respuesta != -1){
                        if( respuesta < comprobarDescargado()){
                            
                            Archivo archivo = new Archivo();
                            archivo.setNombre(_archivo.getNombre());
                            archivo.setRuta(_usuario.getNombre() + "/" + _archivo.getNombre());
                            archivo.setTamaño(comprobarDescargado());
                            Comando comando = new ComandoCargarArchivo(archivo, servidor, _usuario);
                            comando.Ejecutar();
                            
                        }else if( respuesta > comprobarDescargado()){
                            
                            Archivo archivo = new Archivo();
                            archivo.setNombre(_archivo.getNombre());
                            archivo.setDescargado(comprobarDescargado());
                            Comando comando = new ComandoDescargar(archivo,servidor,_usuario);
                            comando.Ejecutar();
                        }
                    }
                }
            }
        } catch (Exception e) {
        }
    }
    
    private void PrepararEnvio(){
        try {
            for (Servidor servidor : Session.getServidores()) {
                servidor.AbrirConexion();
                if(servidor.isActivo()){
                    OutputStream flujoSalida = servidor.getViaComunicacion().getOutputStream();
                    InputStream flujoEntrada = servidor.getViaComunicacion().getInputStream();
                    DataOutputStream salida = new DataOutputStream( flujoSalida );
                    salida.writeUTF(ArchivoXML.CrearMensaje("cargarServidor"));
                    salida.writeUTF(ProxyUsuario.TransformarUsuarioXml(_usuario));
                    salida.writeUTF(ArchivoXML.CrearMensaje(_archivo.getNombre()));
                    salida.writeUTF(ArchivoXML.CrearMensaje(String.valueOf(_archivo.getTamaño())));
                    DataInputStream entrada = new DataInputStream(flujoEntrada);
                    long respuesta = Long.parseLong(ArchivoXML.ObtenerMensaje(entrada.readUTF()));
                    
                    _listaDistribucionSalida.add(new ObjectOutputStream(flujoSalida));
                    _listaDistribucionEntrada.add(entrada);
                }
            }
        } catch (Exception e) {
        }
        
    }
    
    @Override
    public Boolean Ejecutar() {
        try{
            if(!_archivo.isCargando()){
                Sincronizar();     
                PrepararEnvio();
            } 
            OutputStream flujoSalida = _cliente.getOutputStream();
            DataOutputStream salida = new DataOutputStream( flujoSalida );
            salida.writeUTF(ArchivoXML.CrearMensaje(
                    String.valueOf(comprobarDescargado())));
            FileOutputStream fos;
            
            long numero = comprobarDescargado();
            if(comprobarDescargado() != -1){
                
                if(comprobarDescargado() == 0){
                    fos = new FileOutputStream(_usuario.getNombre() 
                            + "/" + _archivo.getNombre());
                }else{
                    
                    fos = new FileOutputStream(_usuario.getNombre() 
                            + "/" + _archivo.getNombre(),true);
                }

                ObjectInputStream ois = new ObjectInputStream(_cliente.getInputStream());
                Object mensajeAux;
                Archivo mensajeRecibido;
                do
                { 
                    mensajeAux = ois.readObject();
                    if (mensajeAux instanceof Archivo){
                        
                        mensajeRecibido = (Archivo) mensajeAux;
                        fos.write(mensajeRecibido.getContenidoFichero(),             
                                 0, mensajeRecibido.getBytesValidos());
                        
                        
                        numero = numero + mensajeRecibido.getBytesValidos();
                        _archivo.setDescargado(_archivo.getDescargado() +
                                mensajeRecibido.getBytesValidos());
                        
                         if(!_archivo.isCargando()){
                            for(int i = 0; i< _listaDistribucionEntrada.size(); i++){
                                _listaDistribucionSalida.get(i).writeObject(mensajeRecibido);
                                _listaDistribucionEntrada.get(i).readUTF();
                            }
                        }
                    } 
                    else{
                        System.err.println("Mensaje no esperado "
                                + mensajeAux.getClass().getName());
                        break;
                    }
                    salida.writeUTF("Listo");
                } while (!mensajeRecibido.isUltimoMensaje());
                fos.flush();
                for(int i = 0; i< _listaDistribucionEntrada.size(); i++){
                    _listaDistribucionSalida.get(i).close();
                    _listaDistribucionEntrada.get(i).close();
                }
                fos.close();
                ois.close();
                _cliente.close();
            }
            
                System.out.println("el archivo esta completo");
            return true;

        } catch (Exception e)
        {
            System.out.println(e);
            return false;
        }
    }
    
}
